//---------------------------------------------------------------------
// Authors: jachymko
//
// Description: Function parameter declaration parser.
//
// Creation Date: Jan 19, 2007
//
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Pscx.Commands.TabExpansion.Parsers
{
    public struct FunctionParameter
    {
        public string Type;
        public string Name;
        public string DefaultValue;
    }

    public class FunctionParameterParser
    {
        private int _index;
        private string _function;

        public FunctionParameterParser(string function)
        {
            _function = function;
        }

        public FunctionParameter[] Parse()
        {
            Match m = _funcParam.Match(_function);
            if (!m.Success)
            {
                return new FunctionParameter[0];
            }

            _index = 0;
            _function = TabExpansionParser.RemoveCommentsAndStrings(m.Groups[1].Value);

            return ParseParameterList();
        }

        private FunctionParameter[] ParseParameterList()
        {
            SkipWhitespace();
            List<FunctionParameter> result = new List<FunctionParameter>();

            do
            {
                _index++;
                result.Add(ParseParameter());
            }
            while (!EOF && Current == ',');

            return result.ToArray();
        }

        private FunctionParameter ParseParameter()
        {
            FunctionParameter p = new FunctionParameter();

            SkipWhitespace();

            if (Current == '[')
            {
                p.Type = ParseType();
            }

            if (Current == '$')
            {
                p.Name = ParseName();
            }

            if (Current == '=')
            {
                p.DefaultValue = ParseDefaultValue();
            }

            return p;
        }

        private string ParseDefaultValue()
        {
            StringBuilder result = new StringBuilder();

            _index++; // skip =
            SkipWhitespace();

            while (!EOF && Current != ')' && Current != ',')
            {
                char ch = Current;
                _index++;

                if (ch == '(' || ch == '{' || ch == '{')
                {
                    SkipToClosingParen(result);
                }
                else if ((ch == '$' || ch == '@') && (Current == '(' || Current == '{'))
                {
                    _index++;
                    SkipToClosingParen(result);
                    _index++;
                }
                else
                {
                    result.Append(ch);
                }
            }

            return result.ToString();
        }

        private void SkipToClosingParen(StringBuilder output)
        {
            int openParens = 1;

            while (!EOF)
            {
                char ch = Current;

                if (ch == '(' || ch == '{' || ch == '[') openParens++;
                if (ch == ')' || ch == '}' || ch == ']') openParens--;

                if (openParens == 0)
                {
                    break;
                }

                if (output != null)
                {
                    output.Append(ch);
                }

                _index++;
            }
        }

        private string ParseName()
        {
            _index++;

            if (Current == '{')
            {
                return ParseEscapedName();
            }

            StringBuilder name = new StringBuilder();

            while (!EOF && !char.IsWhiteSpace(Current) && Current != ',' && Current != '=' && Current != ')')
            {
                name.Append(Current);
                _index++;
            }

            SkipWhitespace();
            return name.ToString();
        }

        private string ParseEscapedName()
        {
            _index++; // skip {

            StringBuilder name = new StringBuilder();

            while (!EOF && Current != '}')
            {
                name.Append(Current);
                _index++;
            }

            _index++; // skip }
            SkipWhitespace();

            return name.ToString();
        }

        private string ParseType()
        {
            //_index++;

            int bracketLevel = 1;
            StringBuilder type = new StringBuilder();

            while (!EOF && bracketLevel > 0)
            {
                if (Current == '[') bracketLevel++;
                if (Current == ']') bracketLevel--;

                type.Append(Current);
                _index++;
            }

            SkipWhitespace();

            return type.ToString();
        }

        private bool EOF
        {
            get { return _index == _function.Length - 1; }
        }

        private char Current
        {
            get { return _function[_index]; }
        }

        private void SkipWhitespace()
        {
            while (char.IsWhiteSpace(Current))
            {
                _index++;
            }
        }

        private static readonly Regex _funcParam = new Regex(@"(?s)^param(.*)");
    }
}

